﻿/* 
* 气泡提示，不兼容ie6
* function:气泡提示效果 
* use:$("selectors").bubble({fn:getdata, width:width, height:height}); 
* 对所有需要气泡提示效果的对象使用bubble方法， 
* fn为气泡中显示内容获得方法,即fn中返回的数据会显示在气泡中 
* 以样式指代div则有: 
* width\height为contents的width\height属性 
* 气泡总width为left.width + contents.width + right.width 
* 气泡总height为top.height + contents.height + bottom.height 
*/
(function($) {
    $.fn.bubble = function(options) {
        Bubble = function() {
            this.defaults = {
                distance: 10,
                time: 250,
                hideDelay: 500,
                width: 100,
                height: 100
            };
            this.options = $.extend(this.defaults, options);
            this.hideDelayTimer = new Array();
            this.shown = new Array();
            this.beingShown = new Array();
            this.popup = new Array();
            this.trigger = new Array();
            this.makebubble = function(w, h) {
                var tpl = $('<div class="bubble-popup"></div>').append('<div class="topleft"></div>').append('<div class="top"></div>').append($('<div class="topright"></div>')).append('<div class="left"></div>').append('<div class="contents"></div>').append('<div class="right"></div>').append('<div class="bottomleft"></div>').append($('<div class="bottom"></div>').append($('<div class="bottomtail"></div>'))).append('<div class="bottomright"></div>').appendTo('body');
                tpl.find('.left, .right, .contents').each(function() {
                    $(this).height(h)
                });
                tpl.find('.top, .bottom, .contents').each(function() {
                    $(this).width(w)
                });
                return tpl;
            };
            this.add = function(triggers, options) {
                //此处的options为每次调用add方法传进来的参数,比如指定获取数据的方法fn, 气泡宽width高height 
                //console.debug("length:"+triggers.length); 
                var t = this.trigger.length;
                //将新加入的需要气泡提示效果的对象放到trigger数组中 
                for (var j = 0; j < triggers.length; j++)
                    this.trigger.push(triggers[j]);
                //console.debug("trigger.length:" + this.trigger.length); 
                var hout = this.handleout;
                var hover = this.handleover;
                var obj = this;
                //为新加入的对象绑定鼠标监听事件 
                triggers.each(function(ind) {
                    $(this).unbind('mouseover').mouseover(function() {
                        hover(t + ind, obj, options);
                    }).unbind('mouseout').mouseout(function() {
                        hout(t + ind, obj, options);
                    });
                });
            };
            this.handleover = function(i, obj, options) {
                //console.debug("hideDelayTimer.length:" + obj.hideDelayTimer.length); 
                //当新触发冒气泡事件时原先的定时器还没结束则将原来的定时器清除 
                if (obj.hideDelayTimer[i]) clearTimeout(obj.hideDelayTimer[i]);
                if (obj.beingShown[i] || obj.shown[i]) {
                    //如果气泡正在冒或已经冒出来了则不再重复冒气泡 
                    return;
                } else {
                    var trigger = $(obj.trigger[i]);
                    //标记正在冒气泡 
                    obj.beingShown[i] = true;
                    //创建气泡 
                    obj.popup[i] = obj.makebubble(options.width || obj.options.width, options.height || obj.options.height);
                    //对于气泡绑定同样的事件以使得鼠标离开触发对象后放到气泡上时气泡不会消失 
                    obj.popup[i].mouseover(function() {
                        obj.handleover(i, obj)
                    }).mouseout(function() {
                        obj.handleout(i, obj)
                    });
                    //调用获取数据的方法fn来显示数据 
                    obj.options.fn(obj.trigger[i], function(data) {
                        obj.popup[i].find('.contents').text(data);
                    });
                    //设定气泡的位置和显示属性,气泡默认出现在触发对象正上方 
                    obj.popup[i].css({
                        top: trigger.offset().top - obj.popup[i].height(),
                        left: trigger.offset().left + trigger.width() / 2 - obj.popup[i].width() / 2,
                        display: 'block'
                    }).animate(
                    //由于万恶的IE不能同时支持PNG半透明和滤镜,所以对于IE不使用滤镜 
                    $.browser.msie ? {
                        top: '-=' + obj.options.distance + 'px'
} : {
    top: '-=' + obj.options.distance + 'px',
    opacity: 1
}, obj.options.time, 'swing', function() {
    obj.beingShown[i] = false;
    obj.shown[i] = true;
});
                    }
                    return false;
                };
                this.handleout = function(i, obj, options) {
                    //console.debug("hideDelayTimer["+i+"]:"+obj.hideDelayTimer[i]); 
                    //处理当因为某些意外操作使得没有触发鼠标进入事件而直接再次触发鼠标离开事件时的情况 
                    if (obj.hideDelayTimer[i]) clearTimeout(obj.hideDelayTimer[i]);
                    obj.hideDelayTimer[i] = setTimeout(function() {
                        obj.hideDelayTimer[i] = null;
                        try {
                            obj.popup[i].animate(
                        $.browser.msie ? {
                            top: '-=' + obj.options.distance + 'px'
} : {
    top: '-=' + obj.options.distance + 'px',
    opacity: 0 //渐隐效果 
}, obj.options.time, 'swing', function() {
    obj.shown[i] = false;
    obj.popup[i].css('display', 'none');
    obj.popup[i] = null;
});
                        } catch (e) { };
                    }, obj.options.hideDelay);
                    return false;
                };
            };
            $.bubble = new Bubble(); //单例 
            $.bubble.add(this, options);
        };
    })(jQuery);